/*
 *  Brno University of Technology
 *
 *  Copyright (C) 2009-2010 by Brno University of Technology and the contributors
 *
 *  Complete list of developers available at our web site:
 *
 *       http://spl.utko.feec.vutbr.cz
 *
 *  This program is free software: you can redistribute it and/or modify
 *  it under the terms of the GNU Lesser General Public License as published by
 *  the Free Software Foundation, either version 3 of the License, or
 *  (at your option) any later version.
 *
 *  This program is distributed in the hope that it will be useful,
 *  but WITHOUT ANY WARRANTY; without even the implied warranty of
 *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
 *  GNU Lesser General Public License for more details.
 *
 *  You should have received a copy of the GNU Lesser General Public License
 *  along with this program.  If not, see http://www.gnu.org/licenses/.
 */

/**
 * Classes related to evolution process.
 */
package cz.vutbr.feec.utko.ef.core;

import java.io.BufferedWriter;
import java.io.FileWriter;
import java.io.IOException;

import org.apache.log4j.Logger;

import cz.vutbr.feec.utko.ef.evolution.IEvolutionSpecifier;
import cz.vutbr.feec.utko.ef.gp.tree.TreeChromozome;
import cz.vutbr.feec.utko.ef.individuals.MutationIsNotPossibleException;

/**
 * The Class Core of evolutionary framework which evolves population. The
 * overall insight in structure of genetic program is depicted in the figure
 * below. The program takes as an input configuration file where information
 * about population is specified (i.e. population size, number of evolutions,
 * mutation and crossover rates etc.). On the other hand the grammar defines the
 * way how the programs should be constructed. It is based on context free
 * grammar theory and represents rules e.g. (A ::= BC | D | F; C ::= c; B ::= c,
 * etc.)
 * 
 * 
 * <br />
 * At the start of an evolution the population is initialized with required
 * number of chromozomes. These chromozomes is represented as a tree of nodes.
 * All the chromozomes are initialized randomly with a maximum height defined
 * (see Node class).
 * 
 * 
 * <br />
 * The evolution specifier defines the way how the chromozomes are mutated and
 * crossovered. The IFitnessEvaluator stands for a class for evaluation of
 * chromozome fitness.
 * 
 * 
 * \image html images/Evolution.png.
 */
public class GProgram {

	/** The log. */
	private static Logger log = Logger.getLogger(GProgram.class);

	/** The configuration of the whole evolution. */
	private Config config;

	/** The population. */
	private Population population;

	/** The evolver defines the behavior of the evolution. */
	private IEvolutionSpecifier evolver;

	/**
	 * Instantiates a new core of evolutionary framework.
	 * 
	 * @param configFileName
	 *            the config
	 * @param grammar
	 *            the grammar
	 * @param e
	 *            the evaluator
	 */
	public GProgram(Config config, IEvolutionSpecifier e) {
		
		this.config = config;
		evolver = e;
		population = new Population();
	}
	/**
	 * Instantiates a new core of evolutionary framework.
	 * 
	 * @param configFileName
	 *            the config
	 * @param grammar
	 *            the grammar
	 * @param e
	 *            the evaluator
	 */
	public GProgram(Config config, IEvolutionSpecifier e, Population initPolupation) {
		
		this.config = config;
		evolver = e;
		population = initPolupation;
	}

	/**
	 * Perform an evolution.
	 * 
	 * @throws MutationIsNotPossibleException
	 */
	private void evolution() {
		population = evolver.evolve(config, population);
	}

	/**
	 * Performs all evolutions.
	 * 
	 * @throws MutationIsNotPossibleException
	 */
	public void evolve() {
		config.update();
		evolver.initPopulation(config, population);
		
		for (int i = 1; i <= config.getEvolutionsNumber(); i++) {
			// perform a single evolution
			evolution();
			//System.out.println(population.getBestIndividual().getCachedFitness());
			log.debug("Population number " + i + ", best:"
					+ population.getIndividual(0).getCachedFitness()
					+ ", no. of evaluations: " + evolver.getNumOfEvaluations());
			
			
			
			// pridal radek vizualizace pro debug mode
			try {
				BufferedWriter out = new BufferedWriter(new FileWriter("bestGramarAfterEvolution.txt"));
				TreeChromozome tch = (TreeChromozome)population.getIndividual(0);
				out.write(tch.generateCode());
				out.close();
			} catch (IOException e) {
				// TODO Auto-generated catch block
				e.printStackTrace();
			}
			
			
			config.update();
		}
	}

	/**
	 * Gets the config.
	 * 
	 * @return the config
	 */
	public Config getConfig() {
		return config;
	}

	/**
	 * Gets the population.
	 * 
	 * @return the population
	 */
	public Population getPopulation() {
		return population;
	}
}
